 #include "cppTutorEnum.h"
 #include "cppTutorTest.h"
 #include "cppTutorArray.h"
 #include "cppTutorUnion.h"
 #include "cppTutorSizeof.h"
 #include "cppTutorGlobals.h"
 #include "cppTutorHeaders.h"
 #include "cppTutorAutoPtr.h" 
 #include "cppTutorPointers.h"
 #include "cppTutorStructure.h"
 #include "cppTutorSpecifiers.h"
 #include "cppTutorLinkedList.h"
 #include "cppTutorReferences.h"
 #include "cppTutorNestedClass.h"
 #include "cppTutorParentClass.h"
 #include "cppTutorFriendClass.h"
 #include "cppTutorAutoPtrTest.h"
 #include "cppTutorNestedFriend.h"
 #include "cppTutorStaticMember.h"
 #include "cppTutorDerivedClass.h"
 #include "cppTutorPolymorphism.h"
 #include "cppTutorPolymorphism.h"
 #include "cppTutorExternKeyword.h"
 #include "cppTutorLinkedListNew.h"
 #include "cppTutorPointersConst.h"
 #include "cppTutorFriendFunction.h"
 #include "cppTutorFunctionPointer.h"
 #include "cppTutorReturningValues.h"
 #include "cppTutorFriendClassTest.h"
 #include "cppTutorCopyConstructor.h"
 #include "cppTutorStackUsingArray.h"
 #include "cppTutorMemoryManagement.h"
 #include "cppTutorConstClassObject.h"
 #include "cppTutorPassingArguments.h"
 #include "cppTutorDoublyLinkedList.h"
 #include "cppTutorConstCorrectness.h"
 #include "cppTutorExceptionHandling.h"
 #include "cppTutorAbstractBaseClass.h"
 #include "cppTutorCircularLinkedList.h"
 #include "cppTutorFunctionOverloading.h"
 #include "cppTutorOperatorOverloading.h"
 #include "cppTutorConstructorChaining.h"
 #include "cppTutorStackUsingLinkedList.h"
 #include "cppTutorOverloadingIOOperator.h"
 #include "cppTutorPureVirtualDestructor.h"
 #include "cppTutorOverloadingUnaryOperator.h"
 #include "cppTutorOverloadingBinaryOperator.h"
 #include "cppTutorOverloadingUsingMemberFunc.h"
 #include "cppTutorOverloadingUnunsualOperators.h"
 #include "cppTutorVirtualCallsInsideDestructors.h"
 #include "cppTutorExceptionHandlingCusTerminate.h"
 #include "cppTutorCopyConstructorVsAssignmentOperator.h"

 // common utils 
 #include "cppTutorUtils.h"
 CcppTutorUtils utl;
 
 // composition and aggregation
 #include "cppTutorComposition.h"
 
 // Interface class
 #include "cppTutorInterfaceClass.h"
 
 // design patterns
 // Creation : Singleton
 #include "cppTutorSingleton.h"
 // Creation : Factory
 #include "cppTutorCreator.h"
 #include "cppTutorConcreteCreator.h"
 // Behavioural : Observer
 #include "cppTutorSubject.h"
 #include "cppTutorObserver.h"
 #include "cppTutorConcreteSubjectClockTimer.h"
 #include "cppTutorConcreteObserverDigitalClock.h"
 #include "cppTutorConcreteObserverAnalogClock.h"
 // Structural  : Facade
 #include "cppTutorFacadePattern.h"
 
 // Inter Process Communication
 // udp socket
 #include "cppTutorSocketClient.h"
 #include "cppTutorSocketServer.h"
 #include "cppTutorSocketApplication.h"
 // tcp socket
 #include "cppTutorTCPSocketServer.h"
 #include "cppTutorTCPSocketClient.h"
 
 // thread
 #include "cppTutorThreadLib.h"
 ThreadLib::Mutex m;
 
  // thread and  multithread
 #include "cppTutorMultiThreading.h"
 
 // Mutex
 #include "cppTutorMultiThreadingMutex.h"

 // C code test header files will be added here
 #include "cppTutor_C_StaticTest_1.h"
 #include "cppTutor_C_StaticTest_2.h"
 #include "cppTutor_C_MemoryManagement.h"

 // Inheritance
 #include "cppTutorInheritance.h"
 #include "cppTutorInheritanceSingle.h"
 
 // log framework
 #include "cppTutorLog.h"
 CcppTutorLog Log;
 
 // mixing C and C++ code
 #include "cppTutorMixing_C_CPP_Common.h"
 #include "cppTutorMixing_C_CPP_C_Code.h" 

 // template
 #include "cppTutorClassTemplate.h"
 #include "cppTutorFunctionTemplate.h"
 
 // C custom thread safe memory manager
 #include "cppTutorMemoryManageTest.h"
 
 // C++ Ox Features
 // unique_ptr
 #include "cppTutorUnique_Ptr.h"
 //shared_ptr
 #include "cppTutorShared_Ptr.h"

 // Standard Template Library (STL)
 // vector 
 #include "cppTutorSTLVector.h"
 // map
 #include "cppTutorSTLMap.h"
 // list
 #include "cppTutorSTLList.h"

 // local class
 #include "cppTutorLocalClass.h"

 //inline function
 #include "cppTutorInline.h"
 
 // const member initialization
 #include "cppTutorConstInitialize.h"

 // virtual function return value override
 #include "cppTutorVirtualFuncReturnOverride.h"
 
 // inheritence
 #include "cppTutorVirtualCallInConstructor.h"

 // tupe casting
 #include "cppTutorTypeCasting.h"
 // static_cast
 #include "cppTutorStaticCast.h"
 // dynamic_cast
 #include "cppTutorDynamicCast.h"

 // pointer to members
 #include "cppTutorPointerToMembers.h"

 #include <exception>
 #include <iostream>
 #include <stdio.h> 

 #ifdef WIN32
    #include <process.h> // system command
 #else
    #include <stdlib.h>
 #endif

 using namespace std;

 int main (int argc, char* argv[])
 {
    Log << "ENTER : main" << endl;
    
    Log << "There are " << argc << " arguments:" << endl;
    // Loop through each argument and print its number and value
    for (int nArg=0; nArg < argc; nArg++) {
        Log << "[" <<nArg << "] : " << " " << argv[nArg] << endl;
    }

    #ifdef WIN32
    system ("cls");
    #else
    system ("clear");
    #endif

    #ifdef WIN32
    string strPath = "../../log/windows/";
    #else
    string strPath = "./log/linux/";
    #endif
	
    displaybanner ();

#ifdef PASSING_VALUES
    {
        int nValue = 10;
        CcppTutorPassingArguments g_PV;
        #ifdef PASS_BY_VALUE
             cout << "Passing " << nValue << " to increase its value by pass by value" << endl;
             g_PV.m_PassByValue (nValue);
             if (nValue == 10)
             {
                 cout << "Pass by value doesn't increase the value !!!" << endl;
             }
             else
             {
                 cout << "Pass by value increases the value" << endl;
             }
        #endif //PASS_BY_VALUE

        #ifdef PASS_BY_REFERENCE
             cout << "Passing " << nValue << " to increase its value by reference" << endl;	 
             g_PV.m_PassByReference (nValue);
             if (nValue == 10)
             {
                 cout << "Pass by reference doesn't increase the value !!!" << endl;
             }
             else
             {
                 cout << "Pass by reference increases the value to " << nValue << endl;
             }
        #endif //PASS_BY_REFERENCE

        #ifdef PASS_BY_ADDRESS
             cout << "Passing " << nValue << " to increase its value by address" << endl;
             g_PV.m_PassByAddress(&nValue);
             if (nValue == 10)
             {
                 cout << "Pass by address doesn't increase the value !!!" << endl;
             }
             else
             {
                 cout << "Pass by address increase the value !!!" << endl;
             }
        #endif //PASS_BY_ADDRESS
    }
#endif //PASSING_VALUES

#ifdef FUNCTION_POINTER
   /* 
    *  "*g_FP.m_fptr" refers to the pointer itself --- "g_FP" tells us where to get the m_fptr value from. But we
    *  still need to give an object that will be the this pointer when we call the function. That's why we need the	          *  "g_FP." prefix.
	*/
    CcppTutorFunctionPointer g_FP;
	(g_FP.*g_FP.m_fptr)();
#endif //FUNCTION_POINTER

#ifdef CONSTRUCTOR_CHAINING
     CcppTutorConstructorChaining g_CnstChain;
	 g_CnstChain.m_CCPerformTask();
#endif //CONSTRUCTOR_CHAINING

#ifdef CONST_CLASS_OBJECTS_AND_MEMBER_FUNCTIONS
	 const CcppTutorConstClassObject cco;
	 cco.m_ConstObject ();
	 // cco.m_temp (); //error C2662: 'CcppTutorConstClassObject::m_temp' : cannot convert 'this' pointer from 'const CcppTutorConstClassObject' to 'CcppTutorConstClassObject &'
     CcppTutorConstClassObject g_ConstCO;
	 g_ConstCO.m_ConstObject ();
#endif //CONST_CLASS_OBJECTS_AND_MEMBER_FUNCTIONS

#ifdef ACCESSING_STATIC_MEMBER
	 cout << "static value : " << CcppTutoStaticMember :: m_sGetValue () << endl;
#endif //ACCESSING_STATIC_MEMBER

#ifdef FRIEND
#ifdef FRIEND_FUNCTION
     CcppTutorFriendFunction g_FrndFn;
	 fGetValue (g_FrndFn);
#endif //FRIEND_FUNCTION

#ifdef FRIEND_CLASS
     CcppTutorFriendClass g_FrndCls;
     CcppTutorFriendClassTest g_FrndClsTst;
	 cout << g_FrndCls.m_accessFriendTestValue (g_FrndClsTst) << endl;
#endif //FRIEND_CLASS

#ifdef NESTED_FRIEND
	 CcppTutorNestedFriend *nf =new CcppTutorNestedFriend;
	 CcppTutorNestedFriend::CFriend f;
	 f.m_FriendAccessNestedFriendData (nf);
	 delete nf;
#endif //NESTED_FRIEND
#endif //FRIEND

#ifdef OPERATOR_OVERLOADING
    #ifdef ARITHMETIC_ADDITION_OPERATOR
	    ccpptutoroperatoroverloading g_opold_1 (20);
 	    ccpptutoroperatoroverloading g_opold_2 (30);
	    g_opold = g_opold_1 + 10;
	    g_opold = 10 + g_opold_1;
	    g_opold = g_opold_1 + g_opold_2;
	    cout << "value = " << g_opold.m_ngetvalue () << endl;
    #endif //ARITHMETIC_ADDITION_OPERATOR

    #ifdef ARITHMETIC_SUBSTRACTION_OPERATOR
	    ccpptutoroperatoroverloading g_opold_1 (30);
 	    ccpptutoroperatoroverloading g_opold_2 (20);
	    
        g_opold = g_opold_1 - g_opold_2;

        CcppTutorOperatorOverloading g_OpOld;
        cout << "Value = " << g_OpOld.m_nGetValue () << endl;
    #endif //ARITHMETIC_SUBSTRACTION_OPERATOR

    #ifdef OVERLOAD_IO_OPERATOR
        CcppTutorOverloadingUsingMemberFunc g_OvrldUMF;
	    CcppTutoOverloadingIOOperator D1(11, 10), D2(5, 11), D3;

	    cout << "First Distance  : " << D1 << endl;
	    cout << "Second Distance : " << D2 << endl;

        cout << "Enter the value of object : " << endl;
	    cin >> D3;
        cout << "Third Distance  : " << D3 << endl;
	
        cout << endl;
    #endif //OVERLOAD_IO_OPERATOR

    #ifdef PREFIX_INCREMENT
	    g_OvrldUMF.m_GetValue ();
	    ++ g_OvrldUMF;
	    g_OvrldUMF.m_GetValue ();
    #endif //PREFIX_INCREMENT

    #ifdef POSTFIX_INCREMENT
	    g_OvrldUMF.m_GetValue ();
        g_OvrldUMF ++;
        g_OvrldUMF.m_GetValue ();
        g_OvrldUMF ++;
        g_OvrldUMF.m_GetValue ();
    #endif //POSTFIX_INCREMENT

    #ifdef ASSIGNMENT_OPERATOR
        CcppTutorOverloadingUsingMemberFunc UMF1(10);
	    CcppTutorOverloadingUsingMemberFunc UMF2 = UMF1;
	    UMF1.m_GetValue ();
	    UMF2.m_GetValue ();
    #endif //ASSIGNMENT_OPERATOR
#endif //OPERATOR_OVERLOADING

#ifdef PURE_VIRTUAL_DESTRUCTOR
    CBase *bs = new CDerived;
    delete bs;

    // object of abstract class type is now allowed
    //CBase *bs = new CBase;
#endif //PURE_VIRTUAL_DESTRUCTOR

#ifdef VIRTUAL_CALL_DESTRUCTOR
    CVirtualCallsInsideDestructorsBase* bp = new CVirtualCallsInsideDestructorsDerived; // Upcast
    delete bp;
#endif //VIRTUAL_CALL_DESTRUCTOR

#ifdef EXCEPTION_HANDLING_CUSTOM_TERMINATE
	try 
	{
		CcppTutorExceptionHandlingCusTerminate b;
		b.f();
	} 
	catch(...) 
	{
		cout << "inside catch(...)" << endl;
	}
#endif

#ifdef REFERENCE
	int nX = 10, nY = 0;
	CcppTutorReferences ref;

	#ifdef USING_REFERENCE
		ref.m_Reference ();
		nY = ref.m_SetValue (nX);
		ref.m_Reference ();
	#endif //USING_REFERENCE

	#ifdef CONST_REFERENCE
		cout << "increamenting the value" << endl;
		ref.m_UseValue (nY);
		ref.m_Reference ();
	#endif //CONST_REFERENCE

	#ifdef POINTER_REFERENCE
	//By running this youll prove to yourself that the pointer is incremented, not what it points to.
	int *nrpValue = &nX;
	ref.m_Reference ();
	ref.m_RefToPointerIncrementValue (nrpValue);
	ref.m_Reference ();
	#endif //POINTER_REFERENCE

#endif //REFERENCE

#ifdef COPY_CONSTRUCTOR
   /*
    * There are 3 situations in which the copy constructor is called:
    * - When we make copy of an object.
    * - When we pass an object as an argument by value to a method.
    * - When we return an object from a method by value.
    */
    //CcppTutorCopyConstructor obj1 (10);
    CcppTutorCopyConstructor obj1 ("saurabh gupta");

    //When we make copy of an object.
    CcppTutorCopyConstructor obj2 (obj1);

    //When we pass an object as an argument by value to a method.
    obj1.m_UseObjectAsArgument (obj1);

    //When we return an object from a method by value.
#endif //COPY_CONSTRUCTOR

#ifdef UNARY_OVERLOADING_OPERATOR
    CcppTutorOverloadingUnaryOperator uop1 (10, 10);
    #ifdef UNARY_OVERLOADING_OPERATOR_USING_FRIEND
        #ifdef UNARY_OVERLOADING_OPERATOR_PLUS
            CcppTutorOverloadingUnaryOperator uop2 = +uop1;
            uop2.m_DisplayValue ();
        #endif //UNARY_OVERLOADING_OPERATOR_PLUS

        #ifdef UNARY_OVERLOADING_OPERATOR_MINUS
            CcppTutorOverloadingUnaryOperator uop2 = -uop1;
            uop2.m_DisplayValue ();
        #endif //UNARY_OVERLOADING_OPERATOR_MINUS

        #ifdef UNARY_OVERLOADING_OPERATOR_PREFIX_INCREMENT
            uop1.m_DisplayValue ();
            CcppTutorOverloadingUnaryOperator uop2 = ++uop1;
            uop2.m_DisplayValue ();
        #endif //UNARY_OVERLOADING_OPERATOR_PREFIX_INCREMENT

        #ifdef UNARY_OVERLOADING_OPERATOR_POSTFIX_INCREMENT
            uop1.m_DisplayValue ();
            uop1 ++;
            uop1.m_DisplayValue ();
        #endif //UNARY_OVERLOADING_OPERATOR_POSTFIX_INCREMENT

        #ifdef UNARY_OVERLOADING_OPERATOR_PREFIX_DECREMENT
            uop1.m_DisplayValue ();
            -- uop1;
            uop1.m_DisplayValue ();
        #endif //UNARY_OVERLOADING_OPERATOR_PREFIX_DECREMENT

        #ifdef UNARY_OVERLOADING_OPERATOR_POSTFIX_DECREMENT
            uop1.m_DisplayValue ();
            uop1 --;
            uop1.m_DisplayValue ();
        #endif //UNARY_OVERLOADING_OPERATOR_POSTFIX_DECREMENT

        #ifdef UNARY_OVERLOADING_OPERATOR_BITWISE_COMPLEMENT
            uop1.m_DisplayValue ();
            ~uop1;
            uop1.m_DisplayValue ();
        #endif //UNARY_OVERLOADING_OPERATOR_BITWISE_COMPLEMENT

        #ifdef UNARY_OVERLOADING_OPERATOR_LOGICAL_NOT
            uop1.m_DisplayValueBool ();
            !uop1;
            uop1.m_DisplayValueBool ();
        #endif //UNARY_OVERLOADING_OPERATOR_LOGICAL_NOT
    #else
        #ifdef UNARY_OVERLOADING_OPERATOR_PLUS
            uop1.m_DisplayValue ();
            CcppTutorOverloadingUnaryOperator uop2 = +uop1;
            uop2.m_DisplayValue ();
        #endif //UNARY_OVERLOADING_OPERATOR_PLUS      

        #ifdef UNARY_OVERLOADING_OPERATOR_MINUS
            uop1.m_DisplayValue ();
            CcppTutorOverloadingUnaryOperator uop2 = -uop1;
            uop2.m_DisplayValue ();
        #endif //UNARY_OVERLOADING_OPERATOR_MINUS  

        #ifdef UNARY_OVERLOADING_OPERATOR_PREFIX_INCREMENT
            uop1.m_DisplayValue ();
            ++ uop1;
            uop1.m_DisplayValue ();
        #endif //UNARY_OVERLOADING_OPERATOR_PREFIX_INCREMENT  

        #ifdef UNARY_OVERLOADING_OPERATOR_POSTFIX_INCREMENT
            uop1.m_DisplayValue ();
            uop1 ++;
            uop1.m_DisplayValue ();
        #endif //UNARY_OVERLOADING_OPERATOR_POSTFIX_INCREMENT  

        #ifdef UNARY_OVERLOADING_OPERATOR_PREFIX_DECREMENT
            uop1.m_DisplayValue ();
            -- uop1;
            uop1.m_DisplayValue ();
        #endif //UNARY_OVERLOADING_OPERATOR_PREFIX_DECREMENT

        #ifdef UNARY_OVERLOADING_OPERATOR_POSTFIX_DECREMENT
            uop1.m_DisplayValue ();
            uop1 --;
            uop1.m_DisplayValue ();
        #endif //UNARY_OVERLOADING_OPERATOR_POSTFIX_DECREMENT

        #ifdef UNARY_OVERLOADING_OPERATOR_BITWISE_COMPLEMENT
            uop1.m_DisplayValue ();
            ~uop1;
            uop1.m_DisplayValue ();
        #endif //UNARY_OVERLOADING_OPERATOR_BITWISE_COMPLEMENT

        #ifdef UNARY_OVERLOADING_OPERATOR_LOGICAL_NOT
            uop1.m_DisplayValueBool ();
            !uop1;
            uop1.m_DisplayValueBool ();        
        #endif
    #endif //UNARY_OVERLOADING_OPERATOR_USING_FRIEND
#endif //UNARY_OVERLOADING_OPERATOR

#ifdef BINARY_OVERLOADING_OPERATOR
    CcppTutorOverloadingBinaryOperator obo1 (10, 10, true, true);
    CcppTutorOverloadingBinaryOperator obo2 (10, 10, true, true);
    #ifdef BINARY_OVERLOADING_OPERATOR_USING_FRIEND
        #ifdef BINARY_OVERLOADING_OPERATOR_ADDITION
            CcppTutorOverloadingBinaryOperator obo3 = obo1 + obo2;
            obo3.m_DisplayValue ();
        #endif //BINARY_OVERLOADING_OPERATOR_ADDITION

        #ifdef BINARY_OVERLOADING_OPERATOR_SUBATRACTION
            CcppTutorOverloadingBinaryOperator obo3 = obo1 - obo2;
            obo3.m_DisplayValue ();            
        #endif //BINARY_OVERLOADING_OPERATOR_SUBATRACTION
    #else
        #ifdef BINARY_OVERLOADING_OPERATOR_ADDITION
            CcppTutorOverloadingBinaryOperator obo3 = obo1 + obo2;
            obo3.m_DisplayValue ();
        #endif //BINARY_OVERLOADING_OPERATOR_ADDITION

        #ifdef BINARY_OVERLOADING_OPERATOR_SUBATRACTION
            CcppTutorOverloadingBinaryOperator obo3 = obo1 - obo2;
            obo3.m_DisplayValue ();            
        #endif //BINARY_OVERLOADING_OPERATOR_SUBATRACTION

        #ifdef BINARY_OVERLOADING_OPERATOR_ADDITION_ASSIGNMENT
            CcppTutorOverloadingBinaryOperator obo3;
            //obo3 += obo1;
            //obo3.m_DisplayValue ();
            obo1 += obo1;
            obo1.m_DisplayValue ();
        #endif

    #endif //BINARY_OVERLOADING_OPERATOR_USING_FRIEND
#endif //BINARY_OVERLOADING_OPERATOR

#ifdef OVERLOADING_STRUCTURE_POINTER
    CcppTutorOverloadingUnunsualOperators a(1, 2, 3), b(4, 5, 6);
    t_ptr ta(false, &a), tb(true, &b);
    ta -> m_Print();    // access denied
    tb -> m_Print();    // access granted
#endif //OVERLOADING_STRUCTURE_POINTER

#ifdef SPECIFIERS
    CcppTutorSpecifiers spc;
    spc.m_PrintSize ();
#endif //SPECIFIERS

#ifdef CASTING
    CcppTutorTypeCasting tc;
    #ifdef STATIC_CAST
        tc.m_StaticCast ();
    #endif //STATIC_CAST

    #ifdef CONST_CAST
        tc.m_ConstCast ();
    #endif //CONST_CAST
    
    #ifdef DYNAMIC_CAST
        tc.m_DynamicCast ();
    #endif //DYNAMIC_CAST
#endif //CASTING
#ifdef CASTING_NEW
     try 
     {
#ifdef STATIC_CAST
         CcppTutorStaticCast *sc = new CcppTutorStaticCast ();
         CcppTutorStaticCastAnother *sca = new CcppTutorStaticCastAnother ();

         someFunc (sc, sca);

         delete sc;
         delete sca;
#endif //STATIC_CAST

#ifdef DYNAMIC_CAST
         CcppTutorDynamicCast *dc = new CcppTutorDynamicCast ();
         CcppTutorDynamicCastAnother *dca = new CcppTutorDynamicCastAnother ();

         someFunc (dc, dca);

         delete dc;
         delete dca;
#endif //DYNAMIC_CAST
     }
     catch (exception& e) {
         cout << "Exception: " << e.what();
     }
#endif //CASTING_NEW

#ifdef INHERITANCE
    #if 0
    CcppTutorBase bs;
    CcppTutorDerived dr;
    //bs.m_BaseGetValue ();
    //dr.m_DerivedGetValue ();
    #endif //0
    #ifdef INHERITANCE_TEST
        CcppTutorCompanyEmployee emp;
        emp.m_Menu ();
    
        CcppTurorCompanyEmployeeManagement memp;
        memp.m_Menu ();
    #endif
    #ifdef PUBLIC_INHERITANCE
        cout << "\n*** Public Inheritance ***\n" << endl;
        cout << "printing values of the base and derived class from outside...." << endl;
        cout << "Access private data - ";
        // cout << "private memebrs of Base class" << dr.m_nBasePriValue << endl;
        cout << "private data not accesible from outside" << endl;

        cout << "Access protected data - ";
        //cout << "protected memebrs of Base class" << dr.m_nBaseProValue << endl;
        cout << "protected data not accesible from outside" << endl;

        cout << "Access public data - ";
        cout << "public memebrs of Base class = " << dr.m_nBasePubValue << endl;
        cout << "public data are accesible from outside" << endl;

        dr.m_DerivedGetBaseValue ();

    #endif
    #ifdef PROTECTED_INHERITANCE
        cout << "\n*** Protected Inheritance ***\n" << endl;
        cout << "printing values of the base class membes in derived ...." << endl;
        cout << "Access private data" << endl;
        //cout << "private memebrs of Base class" << dr.m_nBasePriValue << endl;
        cout << "private data not accesible" << endl;

        cout << "Access protected data" << endl;
        //cout << "protected memebrs of Base class" << dr.m_nBaseProValue << endl;
        cout << "protected data not accesible" << endl;

        cout << "Access public data" << endl;
        //cout << "public memebrs of Base class : " << dr.m_nBasePubValue << endl;
        cout << "public data not accesible when derived in protected inheritence" << endl;

        dr.m_DerivedGetBaseValue ();

    #endif //PROTECTED_INHERITANCE

    #ifdef VIRTUAL_CALL_IN_CONSTRUCTOR
        CVCICDerived der;
    #endif //VIRTUAL_CALL_IN_CONSTRUCTOR

#endif //INHERITANCE

#ifdef POINTER
	CcppTutorPointers ptr;
	#ifdef POINTER_TEST
    #ifdef FUNCTION_POINTER
        char(CcppTutorPointers :: *npPtrFunction)() = &CcppTutorPointers :: m_Display;
        (ptr.*npPtrFunction) ();
    #endif //FUNCTION_POINTER
        ptr.m_Test ();
	#endif //POINTER_TEST
	#ifdef POINTER_ARITHMETIC
	ptr.m_pointerArithmetic ();
	#endif //POINTER_ARITHMETIC
#endif //POINTER

#ifdef NESTED_CLASS
    CcppTutorEnclosingClass ec;
    CcppTutorEnclosingClass :: CcppTutorNestedClass nc;
    ec.m_ECDisplay ();
    nc.m_NCDisplay ();
#endif

#ifdef DATA_STRUCTURE
    #ifdef LINKED_LIST
        #ifdef SINGLE_LINKED_LIST
		    CcppTutorLinkedList lnklst;
		    lnklst.LinkedList_main ();
        #endif //SINGLE_LINKED_LIST

        #ifdef LINKED_LIST_NEW
            List ccplusplus;
            ccplusplus.AddNode (1);
            ccplusplus.AddNode (2);
            ccplusplus.AddNode (3);
            ccplusplus.AddNode (4);
            ccplusplus.AddNode (5);
            ccplusplus.printList ();

            ccplusplus.DeleteData (3);
            ccplusplus.printList ();

            ccplusplus.DeleteData (5);
            ccplusplus.printList ();

            ccplusplus.DeleteData (0);
            ccplusplus.printList ();

            ccplusplus.DeleteData (1);
            ccplusplus.printList ();
        #endif //LINKED_LIST_NEW

        #ifdef CIRCULAR_LINKED_LIST
            CcppTutorCircularLinkedList clinklist;
            clinklist.circular_main ();
        #endif //CIRCULAR_LINKED_LIST

        #ifdef DOUBLY_LINKED_LIST
            CcppTutorDoublyLinkedList dll;
            dll.BuildList ();
            dll.printHeadToTail ();
            dll.printTailToHead ();
        #endif //DOUBLY_LINKED_LIST
    #endif //LINKED_LIST

    #ifdef STACK
        CcppTutorStackUsingArray stack (3);
        #ifdef STACK_USING_ARRAY
        stack.StackMenu ();
        #endif //STACK_USING_ARRAY
    #endif //STACK

    #ifdef STACK_USING_LINKED_LIST
        Stack st;
        st.Push ("Saurabh", 0);
        st.Push ("Sameer", 1);
        st.Push ("Sahil", 2);
        st.Print ();
        cout << "Popping\n";
        st.Pop ();
        cout << "Popping\n";
        st.Pop ();
        cout << "Popping\n";
        st.Pop ();
        cout << "Popping\n";
        st.Pop ();
        // check if we can build another stack
        cout << "\n\nNew Stack\n\n";
        st.Push ("SAURABH", 0);
        st.Push ("SAMEER", 1);
        st.Push ("SAHIL", 2);
        st.Print ();
    #endif //STACK_USING_LINKED_LIST

#endif //DATA_STRUCTURE

#ifdef POLYMORPHISM
    #ifdef VIRTUAL_FUNCTION
        //CcppTutorPolyDerived_1 derived_1 ("Derived");
        //CcppTutorPolyDerived_2 derived_2 ("Derived");
        //CcppTutorPolyBase &base = derived_1;

        //Report (derived_1);
        //Report (derived_2);
        //Report (base);

        CcppTutorPolyDerived_1 *derived_3 = new CcppTutorPolyDerived_1;
        CcppTutorPolyBase *base_1 = derived_3;
        delete base_1;
    #else
        CcppTutorPolyBase base;
        CcppTutorPolyDerived_1 derived_1;
        CcppTutorPolyDerived_2 derived_2;

        base.m_Report (base);
        derived_1.m_Report (derived_1);
        derived_2.m_Report (derived_2);
    #endif
#endif //POLYMORPHISM

#ifdef SIZE_OF_CLASS_WITH_VIRTUAL
    cout << "int: " << sizeof(int) << endl;
    cout << "NoVirtual: " << sizeof(CcppTutorNoVirtual) << endl;
#ifdef ONE_VIRTUAL
    cout << "sizeof(void*) : " << sizeof(void*) << endl;
    cout << "OneVirtual: " << sizeof(CcppTutorOneVirtual) << endl;
#endif //ONE_VIRTUAL
#ifdef TWO_VIRTUAL
    cout << "TwoVirtuals: " << sizeof(CcppTutorTwoVirtuals) << endl;
#endif //TWO_VIRTUAL
#endif //SIZE_OF_CLASS_WITH_VIRTUAL

#ifdef ABSTRACT_BASE_CLASS
    //error C2259: 'CcppTutorAbstractBaseClass' : cannot instantiate abstract class
    //CcppTutorAbstractBaseClass abs;
    CcppTutorInheritAbstractBaseClass iabs;
    iabs.m_TaskFirst ();
    iabs.m_TaskSecond ();
#endif //ABSTRACT_BASE_CLASS

#ifdef INTERFACCE_CLASS
    CcppTutorInterfacceImplementation iim;
    iim.m_ITaskFirst ();
    iim.m_ITaskSecond ();
#endif //INTERFACCE_CLASS

#ifdef COMPOSITION
    // Create a teacher outside the scope of theDepartment 
    Teacher *pTeacher = new Teacher("Bob"); // create a teacher
    {
        // Create a department and use the constructor parameter to pass the teacher to it.
        Department cDept(pTeacher);
    } // cDept goes out of scope here and is destroyed

    // pTeacher still exists here because cDept did not destroy it
    delete pTeacher;    
#endif //COMPOSITION

#ifdef COPY_CONSTRUCTOR_VS_ASSIGNMENTOPERATOR
#if 0
	CcppTutorCopyConstructorVsAssignmentOperator ccao1 ("ccplusplus.com");
	if (true)
	{
		CcppTutorCopyConstructorVsAssignmentOperator ccao2 = ccao1;
		ccao2.m_GetValue ();
	}

	ccao1.m_GetValue ();
#endif
	CcppTutorCopyConstructorVsAssignmentOperator ccao1 ("ccplusplus.com");
	CcppTutorCopyConstructorVsAssignmentOperator ccao2;
	if (true)
	{
		ccao2 = ccao1;
		ccao2.m_GetValue ();
	}
	ccao1.m_GetValue ();

#endif //COPY_CONSTRUCTOR_VS_ASSIGNMENTOPERATOR

#ifdef INTER_PROCESS_COMMUNICATION
    #ifdef MULTITHREADING
        CcppTutorMultiThreading thread;
        #ifdef MULTI_THREAD
            thread.m_CreateThread ();
            thread.m_JoiningDetachingThreads ();
        #else
            thread.m_CreateThread ();
        #endif //MULTI_THREAD
    #endif //MULTITHREADING

    #ifdef MUTEX_DEMO
        CcppTutorMultiThreading thread;
        mutexDemo ();
    #endif //MUTEX_DEMO
    
    #ifdef THREAD_LIB
        StartThread ();
    #endif //THREAD_LIB
    #ifdef SOCKET
    {
        int nUserChoice = 0, bFlagStatus = true;
        while (bFlagStatus)
        {
            cout << "Supported Modes :-" << endl;
            cout << "1.     TCP        " << endl;
            cout << "2.     UDP        " << endl;
            cout << "9.     Exit       " << endl;
            cout << endl;
            cout << "Select the desired mode" << endl;
            cin  >> nUserChoice;
            switch (nUserChoice)
            {
                case 1:
                    while (bFlagStatus)
                    {
                        cout << "Supported Types :-" << endl;
                        cout << "1.     Server     " << endl;
                        cout << "2.     Client     " << endl;
                        cout << "9.     Exit       " << endl;
                        cout << endl;
                        cout << "Select the desired Type" << endl;
                        nUserChoice = 0;
                        cin  >> nUserChoice;
                        if (nUserChoice == 1)
                        {
                            cout << "creating socket server in TCP mode" << endl;
                            #if 0
                            sock_server_tcp (argc, argv);
                            #endif //0
                            CcppTutorTCPSocketServer tcpserver ("9999");
                            tcpserver.ServerMain ();
                        }
                        else if (nUserChoice == 2)
                        {
                            cout << "creating socket client in TCP mode" << endl;
                            #if 0
                            sock_client_tcp (argc, argv);
                            #endif //0
                            CcppTutorTCPSocketClient tcpclient;
                            tcpclient.ClientMain ();
                        }
                        else if (nUserChoice == 9)
                        {
                            cout << "Exiting" << endl;
                            bFlagStatus = false;
                        }
                        else
                        {
                            cout << "Unsupported Choice." << endl;
                        }
                    };
                    break;
                case 2:
                    bFlagStatus = true;
                    while (bFlagStatus)
                    {
                        cout << "Supported Types :-" << endl;
                        cout << "1.     Server     " << endl;
                        cout << "2.     Client     " << endl;
                        cout << "9.     Exit       " << endl;
                        cout << endl;
                        cout << "Select the desired Type" << endl;
                        nUserChoice = 0;
                        cin  >> nUserChoice;
                        if (nUserChoice == 1)
                        {
                            cout << "creating socket server in TCP mode" << endl;
                            //CcppTutorSocketServer server;
                            //server.udp_server (argc, argv);                        
                        }
                        else if (nUserChoice == 2)
                        {
                            cout << "creating socket client in TCP mode" << endl;
                            //CcppTutorSocketClient client;
                            //client.udp_client (argc, argv);
                        }
                        else if (nUserChoice == 9)
                        {
                            cout << "Exiting" << endl;
                            bFlagStatus = false;
                        }
                        else
                        {
                            cout << "Unsupported Choice." << endl;
                        }
                    };                
                    break;
                case 9:
                    bFlagStatus = false;
                    break;
                default:
                    cout << "Unsupported choice. Please try again..." << endl;
                    break;
            };
        };
    }
        // #ifdef SOCKET_UDP
            // #ifdef SOCKET_SERVER
                // CcppTutorSocketServer server;
                // server.udp_server (argc, argv);
            // #endif //SOCKET_SERVER
            // #ifdef SOCKET_CLIENT
                // CcppTutorSocketClient client;
                // client.udp_client (argc, argv);
            // #endif //SOCKET_CLIENT
        // #endif //SOCKET_UDP
        
        #ifdef SOCKET_TCP
		
        #endif //SOCKET_TCP
    #endif //SOCKET
#endif //INTER_PROCESS_COMMUNICATION

#ifdef	UNION
	CcppTutorUnion un;
	un.m_GetUnionSize();
#endif //UNION

#ifdef	SIMPLE_STRUCTURE
	CcppTutorStructure st;
	st.m_SimpleStructure ();
#endif //STRUCTURE

#ifdef TYPEDEF_WITH_STRUCT
	CcppTutorStructure tpst;
	tpst.m_TypedefWithStructure ();
#endif //TYPEDEF_WITH_STRUCT

#ifdef POINTERS_TO_STRUCTS
	CcppTutorStructure pst;
	pst.m_PointerToStructure ();
#endif //POINTERS_TO_STRUCTS

#ifdef ENUM
	CcppTutorEnum enm;
	enm.m_Enum ();
	enm.m_PrintEnumValues ();
#endif //ENUM

#ifdef ARRAY
    CcppTutorArray array;
#ifdef POINTERS_AND_BRACKETS
    array.m_PointersAndBrackets ();
#endif //POINTERS_AND_BRACKETS

#ifdef PASSING_ARRAY_AS_ARGUMENT
    int nArray[10];
    array.m_InitializeArray (nArray, 10);
    array.m_PrintArray (nArray, 10);
#endif //PASSING_ARRAY_AS_ARGUMENT
#endif //ARRAY


#ifdef SIZEOF
    CcppTutorSizeof szof;
    szof.m_Sizeof ();
    cout << endl;
    cout << "sizeof (szof.m_pnHello)\t= " << sizeof (szof.m_pnHello) << endl;
    cout << "sizeof (szof.m_pcHello)\t= " << sizeof (szof.m_pcHello) << endl;
    char pcHello [] = "GlobalLogic";
    char *pcHello1 = "GlobalLogic";
    cout << "sizeof (pnHello) = " << sizeof (pcHello) << endl;
    cout << "strlen (pcHello) = " << strlen (pcHello) << endl;
    cout << "sizeof (pcHello1) = " << sizeof (pcHello1) << endl;    
    cout << "strlen (pcHello1) = " << strlen (pcHello1) << endl;

   /*
    * x64 LINUX output
    *
    sizeof (char)            =      1
    sizeof (short)           =      2
    sizeof (int)             =      4
    sizeof (long)            =      8
    sizeof (float)           =      4
    sizeof (double)          =      8
    sizeof (long double)     =      16
    sizeof (Primitives)      =      48

    sizeof (szof.m_pnHello) = 8
    sizeof (szof.m_pcHello) = 8
    strlen (pcHello) = 11
    strlen (pcHello1) = 11
    sizeof (pcHello1) = 8
	-----------------------------
	*
	* x64 WIN32
	*
	sizeof (char)            =      1
	sizeof (short)           =      2
	sizeof (int)             =      4
	sizeof (long)            =      4
	sizeof (float)           =      4
	sizeof (double)          =      8
	sizeof (long double)     =      8
	sizeof (Primitives)      =      32

	sizeof (szof.m_pnHello) = 4
	sizeof (szof.m_pcHello) = 4
	strlen (pcHello) = 11
	strlen (pcHello1) = 11
	sizeof (pcHello1) = 4
	*/
#endif //SIZEOF


#ifdef DESIGN_PATTERN
    #ifdef CREATIONAL
	    #ifdef SINGLETON
	       CcppTutorSingleton *sc1,*sc2;  
	       sc1 = CcppTutorSingleton::getInstance();  
	       sc1->method();  
	       sc2 = CcppTutorSingleton::getInstance();  
	       sc2->method();  
	    #endif // SINGLETON
        #ifdef FACTORY
            //Create two types of documents - constructors call Factory method
            Document* doc1 = new Resume();
            Document* doc2 = new Report();

            //Get and print the pages of the first document
            list<Page*>& doc1Pages = const_cast<list<Page*>&> (doc1->GetPages());
            cout << "\nResume Pages -------------" << endl;
            for(list<Page*>::iterator it = doc1Pages.begin(); it != doc1Pages.end(); it++)
            {
                cout << "\t" << (*it)->GetPageName() << endl;
            }

            //Get and print the pages of the second document
            list<Page*>& doc2Pages = const_cast<list<Page*>&> (doc2->GetPages());
            cout << "\nReport Pages -------------" << endl;
            for(list<Page*>::iterator it = doc2Pages.begin(); it != doc2Pages.end(); it++)
            {
                cout << "\t" << (*it)->GetPageName() << endl;
            }
        #endif //FACTORY
    #endif //CREATIONAL

    #ifdef BEHAVIOURAL
        #ifdef OBSERVER
            ClockTimer timer;
            DigitalClock digitalClock(&timer);
            AnalogClock analogClock(&timer);
     
            // subject state change and update all it's
            // observers which are digitalClock and
            // analogClock in this program
            timer.Tick();      
        #endif //OBSERVER
    #endif //BEHAVIOURAL
    
    #ifdef STRUCTURAL_PATTERN
        #ifdef FACADE
            CcppTutorFacadePattern fp;
            fp.startCooler ();
        #endif //FACADE
    #endif //STRUCTURAL_PATTERN

#endif //DESIGN_PATTERN

#ifdef C
    #ifdef MEMORY_MANAGEMENT
        GetMemory ();
    #endif //MEMORY_MANAGEMENT

    #ifdef STATIC
        StaticTest_1 ();
        int nX = StaticTest_1_1 ();
        printf ("received static variable value from function return value = %d\n", nX);
        StaticTest_2 ();
    #endif //STATIC
    
    #ifdef MY_MEMORY_MANAGER
        memoryManagerTest ();
    #endif //MY_MEMORY_MANAGER
#endif //C

#ifdef AUTO_PTR
    // CcppTutorAutoPtr <CcppTutorAutoPtrTest> apt (new CcppTutorAutoPtrTest ());
    // apt->m_PrintInfo ();
    {
        //dummy brace to test the destruction
        CcppTutorAutoPtr <CcppTutorAutoPtrTest> apt(new CcppTutorAutoPtrTest("Saurabh Gupta", 29));

        //test the -> operator
        cout << "Name: " << apt->m_GetName() << ", Age: " << apt->m_GetAge() << "\n";

        //test the transfer of ownership in copy constructor
        CcppTutorAutoPtr<CcppTutorAutoPtrTest> apt2(apt);

        //test the * operator
        cout << "Name: " << (*apt2).m_GetName() << ", Age: " << (*apt2).m_GetAge() << "\n";

        //test the transfer of ownership in assignment operator
        CcppTutorAutoPtr<CcppTutorAutoPtrTest> apt3;
        apt3 = apt2;

        //test the get function
        cout << "Name: " << apt3.get()->m_GetName() << ", Age: " << apt3.get()->m_GetAge() << "\n";

        //lets test the reset function
        apt3.reset(new CcppTutorAutoPtrTest("Shalini Gupta", 28));

        //test the get function
        cout << "Name: " << apt3.get()->m_GetName() << ", Age: " << apt3.get()->m_GetAge() << "\n";

        //finally lets test the release function
        CcppTutorAutoPtr<CcppTutorAutoPtrTest> apt4(apt3.release());

        cout << "Name: " << apt4.get()->m_GetName() << ", Age: " << apt4.get()->m_GetAge() << "\n";
    }    
#endif //AUTO_PTR

#ifdef STANDARD_TEMPLATE_LIBRARY
    #ifdef STL_VECTOR
        CcppTutorSTLVector stl;
        stl.showMenu ();
    #endif //STL_VECTOR
    
    #ifdef STL_MAP
        CcppTutorSTLMap mymap;
        mymap.m_mapDemo ();
    #endif //STL_MAP
    
    #ifdef STL_LIST
        CcppTutorSTLList mylist;
        mylist.m_listDemo ();
    #endif //STL_LIST
    
#endif //STANDARD_TEMPLATE_LIBRARY
        
#ifdef MEMORY_MANAGEMENT_CPP
    CcppTutorMemoryManagement mm;
#endif //MEMORY_MANAGEMENT_CPP        
        
#ifdef CONST_CORRECTNESS
    CcppTutorConstCorrectness ctns (10);
    #ifdef POINTER_TO_A_CONSTANT
        ctns.m_Display ();
        ctns.m_Change ();
        ctns.m_Display ();    
        // creating a pointer to a const object, cnts1 points to a constant CcppTutorConstCorrectness
        CcppTutorConstCorrectness const* cnts1;
        //error: request for member m_Change in cnts1, which is of non-class type const CcppTutorConstCorrectness*
        cnts1.m_Change ();
    #endif //POINTER_TO_A_CONSTANT

    #ifdef CONST_POINTER
        ctns.m_Display ();
        ctns.m_Change ();
        ctns.m_Display ();    
        CcppTutorConstCorrectness *const cnts2 = &ctns;
        //error: assignment of read-only variable âcnts2
        //cnts2 = &ctns;
        ctns.m_Display ();
        ctns.m_Change ();
        ctns.m_Display ();
    #endif //CONST_POINTER
 
    #ifdef CONSTANT_POINTER_TO_A_CONSTANT
        CcppTutorConstCorrectness const* const ctns3;
    #endif //CONSTANT_POINTER_TO_A_CONSTANT
#endif //CONST_CORRECTNESS        
  
#ifdef MIXING_C_CPP
    Fred fred;
    c_function(&fred);
#endif //MIXING_C_CPP
  
#ifdef TEMPLATE
    #ifdef FUNCTION_TEMPLATE
        int nA = 0, nB = 0;
        float fA = 0.0, fB = 0.0;
        cout << "Enter two interger values" << endl;
        cin  >> nA >> nB;
        getSum <int>(nA, nB);
        cout << "Enter two float values" << endl;
        cin  >> fA >> fB;
        getSum <float>(fA, fB);
    #endif //FUNCTION_TEMPLATE
   
    #ifdef CLASS_TEMPLATE
	    int nFirst, nSecond;
        float fFirst, fSecond;
	    cout << "Enter 1st integer number : " << endl;
	    cin >> nFirst;
	    cout << "Enter 2nd integer number : " << endl;
	    cin >> nSecond;
	    cout << "Calculating the biggest number from " << nFirst << " and " << nSecond << " !!!" << endl;
	    CcppTutorFunctionTemplate <int> myobject1 (nFirst, nSecond );
        cout << myobject1.getmax();
        cout << endl;

	    cout << "Enter 1st float number : " << endl;
	    cin >> fFirst;
	    cout << "Enter 2nd float number : " << endl;
	    cin >> fSecond;
	    cout << "Calculating the biggest number from " << fFirst << " and " << fSecond << " !!!" << endl;
	    cout << "Biggest number is ";
        CcppTutorFunctionTemplate <float> myobject2 (fFirst, fSecond );
	    cout << myobject2.getmax();
    #endif //CLASS_TEMPLATE
#endif //TEMPLATE

#ifdef CPP_OX
    #ifdef UNIQUE_PTR
        uniquePtr ();
    #endif //UNIQUE_PTR
    
    #ifdef SHARED_PTR
        sharedPtr ();
    #endif //SHARED_PTR
#endif //CPP_OX

#ifdef LOCAL_CLASS
    CcppTutorLocalClass lc;
    lc.m_InterfaceMethod ();
    //CcppTutorLocalClass :: CLocal lo;
#endif //LOCAL_CLASS

#ifdef INLINE_FUNCTION
    CcppTutorInline iline;
    iline.m_Inline ();
#endif //INLINE_FUNCTION

#ifdef CONST_INITIALIZE
    #ifdef CONST_INITIALIZE_USING_INITIALIZER_LIST
        CcppTutorConstInitialize cini;
    #endif //CONST_INITIALIZE_USING_INITIALIZER_LIST
    
    #ifdef CONST_INITIALIZE_ASSIGNEMNT_INSIDE_CONSTRUCTOR
        CcppTutorConstInitialize cini;
    #endif //CONST_INITIALIZE_ASSIGNEMNT_INSIDE_CONSTRUCTOR
    
#endif //CONST_INITIALIZE
    cout << "\n##################################################\n";
    Log << "EXIT  : main" << endl;

#ifdef OVERRIDE_VIRTUAL_FUNC_RETURN
    CDerivedVFRO drv1;
    CcppTutorVirtualFuncReturnOverride* vfro1 = &drv1;
    vfro1->test ();
#endif //OVERRIDE_VIRTUAL_FUNC_RETURN

#ifdef POINTER_TO_MEMBERS
    #ifdef POINTER_TO_MEMBERS_DATA
         CcppTutorPointerToMembers *ptm = new CcppTutorPointerToMembers, ptm1;
         // pointer to member variable
         int CcppTutorPointerToMembers :: *pPtm;

         ptm->m_Print ();
         pPtm = &CcppTutorPointerToMembers :: m_nValue;
         ptm->*pPtm = 500;
         ptm->m_Print ();

         ptm1.m_Print ();
         pPtm = &CcppTutorPointerToMembers :: m_nValue1;
         ptm1.*pPtm = 1000;
         ptm1.m_Print ();
         delete ptm;
    #endif //POINTER_TO_MEMBERS_DATA

    #ifdef POINTER_TO_MEMBERS_FUNCTION
         // pointer to member function
         CcppTutorPointerToMembers *ptm2 = new CcppTutorPointerToMembers;
         void (CcppTutorPointerToMembers::*fptr) (void) = &CcppTutorPointerToMembers :: m_Speak;
         (ptm2->*fptr)();
    #endif //POINTER_TO_MEMBERS_FUNCTION
#endif //POINTER_TO_MEMBERS
    return 0;
 }
